﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;
using SCTO.Center;
using Vive.Crypto;

namespace Scto
{
    class Program
    {
        static void Main(string[] args)
        {
            var lastSm4Key = "";
            var sm2 = Vive.Crypto.CryptoFactory.CreateAsymmetric(AsymmetricProviderType.SM2);
            var sm3 = Vive.Crypto.CryptoFactory.CreateHashing(HashingProviderType.SM3);
            var sm4 = Vive.Crypto.CryptoFactory.CreateSymmetric(SymmetricProviderType.SM4);

            var sm2Key = sm2.CreateKey();
            Console.WriteLine($"sm2公钥:{sm2Key.PublickKey}");
            Console.WriteLine($"sm2私钥:{sm2Key.PrivateKey}");

            Console.Write("请输入监听IP：");
            var epStr = Console.ReadLine();
            var success = IPEndPoint.TryParse(epStr, out var ip);
            var baseUrl = "";
            if (!success)
            {
                Console.WriteLine("输入的不是合法IP");
                return;
            }
            var client = new UdpClient(ip);
            Task.Run(() =>
            {
                while (true)
                {
                    IPEndPoint ep = IPEndPoint.Parse(epStr);
                    var data = client.Receive(ref ep);
                    var dataStr = Encoding.UTF8.GetString(data);
                    if (dataStr.Contains('|'))
                    {
                        var dataArr = dataStr.Split('|');
                        var remoteEp = IPEndPoint.Parse(dataArr[0]);
                        Console.WriteLine($"接收到来自{dataArr[0]}的文件下载请求:{dataArr[2]}.");
                        var sm4Key = sm2.Decrypt(dataArr[1], sm2Key.PrivateKey);
                        Console.WriteLine($"约定SM4密钥:{sm4Key}");
                        var content = sm4.Encrypt(File.ReadAllText(dataArr[2]), sm4Key);
                        var datagram = Encoding.UTF8.GetBytes(content);
                        Task.Delay(500);
                        var sendClient = new UdpClient();
                        sendClient.SendAsync(datagram, datagram.Length, remoteEp);
                        Console.WriteLine("文件已发送.");
                    }
                    else
                    {
                        Console.Write($"接收到加密文件，使用SM4密钥{lastSm4Key}解密:");
                        Console.WriteLine(sm4.Decrypt(dataStr, lastSm4Key));
                    }
                }
            });
            Console.WriteLine($"欢迎，{ip}");
            while (true)
            {
                Console.WriteLine("选择功能:");
                Console.WriteLine("1-连接中心服务器  2-获取文件列表  3-获取文件节点信息  4-注册(上传)文件  5-下载文件");
                var selection = Console.ReadKey(true);
                switch (selection.Key)
                {
                    case ConsoleKey.D1:
                        {
                            Console.Write("输入中心服务器基地址:");
                            baseUrl = Console.ReadLine();
                            var res = $"{baseUrl}/scto/register".PostUrlEncodedAsync(new
                            {
                                clientId = epStr,
                                pubKey = sm2Key.PublickKey
                            }).Result;
                            if (res.StatusCode == 200)
                            {
                                Console.WriteLine("连接成功");
                            }
                            else
                            {
                                Console.Write("连接失败");
                            }
                        }
                        break;
                    case ConsoleKey.D2:
                        {
                            var res = $"{baseUrl}/scto/file".GetJsonAsync<List<SctoFileInfo>>().Result;
                            Console.WriteLine($"获取到{res.Count}个文件:");
                            foreach(var file in res)
                            {
                                Console.WriteLine(file.ToString());
                            }
                        }
                        break;
                    case ConsoleKey.D3:
                        {
                            Console.Write("输入文件名:");
                            var fileName =Console.ReadLine();
                            var res = $"{baseUrl}/scto/file?fileName={fileName}".GetJsonAsync<List<ClientInfo>>().Result;
                            Console.WriteLine($"获取到{res.Count}个节点信息:");
                            foreach (var clientInfo in res)
                            {
                                Console.WriteLine($"IP:{clientInfo.Client} PubKey:{clientInfo.PublicKey}");
                            }
                        }
                        break;
                    case ConsoleKey.D4:
                        {
                            Console.Write("输入文件名(暂时仅支持同级目录下文件):");
                            var file = Console.ReadLine();
                            if (!File.Exists(file))
                            {
                                Console.WriteLine("文件不存在");
                                continue;
                            }
                            $"{baseUrl}/scto/upload".PostUrlEncodedAsync(new
                            {
                                clientId = epStr,
                                fileName = file,
                                fileSignature = sm3.Signature(File.ReadAllText(file), null)
                            }).Wait();
                            Console.WriteLine("操作完成");
                        }
                        break;
                    case ConsoleKey.D5:
                        {
                            Console.Write("输入节点IP:");
                            var ipStr = Console.ReadLine();
                            var parseSuccess = IPEndPoint.TryParse(ipStr, out var fileIp);
                            if (!parseSuccess)
                            {
                                Console.WriteLine("输入的不是合法IP");
                                return;
                            }
                            Console.Write("输入节点公钥:");
                            var fileSm2Key = Console.ReadLine();
                            Console.Write("输入文件名:");
                            var fileName = Console.ReadLine();
                            var random = new Random();
                            var key = sm3.Signature(random.NextDouble().ToString(), null);
                            Console.WriteLine($"约定SM4加密密钥:{key}");
                            var encryptedSm4Key = sm2.Encrypt(key, fileSm2Key);
                            lastSm4Key = key;
                            Console.WriteLine($"使用节点SM2公钥对SM4密钥进行加密:{encryptedSm4Key}");
                            var datagram = $"{epStr}|{encryptedSm4Key}|{fileName}";
                            var data = Encoding.UTF8.GetBytes(datagram);
                            client.Send(data, data.Length, fileIp);
                            Console.WriteLine("下载请求已发送");
                        }
                        break;
                }
            }
        }
    }
}
